package com.maxd.service;

import com.google.common.collect.Lists;
import com.maxd.adapter.LoginUserHolder;
import com.maxd.error.ExceptionEnum;
import com.maxd.model.*;
import com.maxd.respository.ClassInfoRepository;
import com.maxd.respository.ClassStudentInfoRepository;
import com.maxd.respository.StudentInfoRepository;
import com.maxd.respository.selfOrder.OrdersRepository;
import com.maxd.utils.AssertUtil;
import com.maxd.utils.DateUtils;
import com.maxd.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.persistence.criteria.Predicate;
import java.util.Date;
import java.util.List;

@Component
@Slf4j
public class ClassStudentService {
    
    @Autowired
    private ClassInfoRepository classInfoRepository;

    @Autowired
    private StudentInfoRepository studentInfoRepository;
    
    @Autowired
    private ClassStudentInfoRepository classStudentInfoRepository;

    @Autowired
    private OrdersRepository ordersRepository;

    @Value("${classes.lesson}")
    private Long lessonTypeId;

    private static final List<Integer> EFFECT_STATUS = Lists.newArrayList(2,3,4,6,8,9,10);

    public List<ClassStudentInfo> queryList(Long classId, String effect, String orderId) {
        log.info("查询班级班级学员信息，查询条件: classId = {}, effect = {}", classId, effect);
        Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
        Specification<ClassStudentInfo> queryCondition = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            if(classId != null) {
                predicates.add(criteriaBuilder.equal(root.get("classId"), classId));
            }
            if("1".equals(effect)) {
                String date = DateUtils.getDate();
                predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("effectTime"), date));
                predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("expireTime"), date));
            }
            if(StringUtils.isNotEmpty(orderId)) {
                predicates.add(criteriaBuilder.equal(root.get("orderId"), orderId));
            }
            predicates.add(criteriaBuilder.equal(root.get("status"), "1"));
            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        List<ClassStudentInfo> studentInfos = classStudentInfoRepository.findAll(queryCondition, sort);
        log.info("查询到班级学员信息为:{}", JsonUtils.toJsonString(studentInfos));
        return studentInfos;
    }

    public void addStudent(ClassStudentInfo classStudentInfo) {
        Long classId = classStudentInfo.getClassId();
        Long studentId = classStudentInfo.getStudentId();
        String orderId = classStudentInfo.getOrderId();

        ClassInfo classInfo = classInfoRepository.findById(classId).orElse(null);
        AssertUtil.notNull(classInfo, ExceptionEnum.CLASS_NOF);

        StudentInfo studentInfo = studentInfoRepository.findById(studentId).orElse(null);
        AssertUtil.notNull(studentInfo, ExceptionEnum.STUDENT_NOF);

        List<Orders> ordersList = ordersRepository.findByOrderId(orderId);
        AssertUtil.assertTrue(!CollectionUtils.isEmpty(ordersList), ExceptionEnum.ORDER_NOF);

        Orders orders = ordersList.get(0);
        log.info("关联的订单信息:{}", JsonUtils.toJsonString(orders));

        AssertUtil.assertTrue(studentInfo.getUserId().equals(orders.getUserId()), ExceptionEnum.ORDER_NOT_MATCH);
        AssertUtil.assertTrue(isEffect(orders.getStatus()), ExceptionEnum.ORDER_NOT_MATCH);
        AssertUtil.assertTrue(lessonTypeId.equals(orders.getType()), ExceptionEnum.ORDER_NOT_MATCH);
        // 订单是否被关联过
        //List<ClassStudentInfo> usedRec = this.queryList(null, null, orders.getOrderNum());
        //AssertUtil.assertTrue(CollectionUtils.isEmpty(usedRec) || usedRec.get(0).getId().equals(classStudentInfo.getId()), ExceptionEnum.ORDER_USED);

        classStudentInfo.setClassName(classInfo.getName());
        classStudentInfo.setStudentName(studentInfo.getName());
        classStudentInfo.setUserId(studentInfo.getUserId());
        if(StringUtils.isEmpty(classStudentInfo.getStatus())) {
            classStudentInfo.setStatus("1");
        }

        List<ClassStudentInfo> classStudentInfos = queryList(studentId, classId);
        boolean notExists = CollectionUtils.isEmpty(classStudentInfos) || classStudentInfos.stream().anyMatch(e -> e.getId().equals(classStudentInfo.getId()));
        AssertUtil.assertTrue(notExists, ExceptionEnum.CLASS_STUDENT_EXISTS);

        if(classStudentInfo.getId() == null) {
            classStudentInfo.setCreateBy(LoginUserHolder.getAdminId());
            classStudentInfo.setUpdateBy(LoginUserHolder.getAdminId());
        } else {
            classStudentInfo.setUpdateBy(LoginUserHolder.getAdminId());
            classStudentInfo.setUpdateTime(new Date());
        }
        classStudentInfoRepository.save(classStudentInfo);
    }

    private List<ClassStudentInfo> queryList(Long studentId, Long classId) {
        Specification<ClassStudentInfo> queryCondition = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            if(studentId != null) {
                predicates.add(criteriaBuilder.equal(root.get("studentId"), studentId));
            }
            if(classId != null) {
                predicates.add(criteriaBuilder.equal(root.get("classId"), classId));
            }
            predicates.add(criteriaBuilder.equal(root.get("status"), "1"));
            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        return classStudentInfoRepository.findAll(queryCondition);

    }

    private boolean isEffect(Integer status) {
        return status != null && EFFECT_STATUS.contains(status);
    }
}
